home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 21 / Cream of the Crop 21 (Terry Blount) (October 1996).iso / os2 / nortutil.zip / src / Spew / spew.c < prev   
C/C++ Source or Header  |  1996-08-28  |  15KB  |  623 lines

  1. /*
  2.  * SPEW.C
  3.  */
  4. #ifndef lint
  5. static char *cpr[]={
  6. "  Copyright 1987 Greg Smith",
  7. "  Permission is granted to freely use and distribute this software",
  8. "provided this notice is left attached and no monetary gain is made."
  9. };
  10. #endif
  11. #include <stdio.h>
  12. #include <ctype.h>
  13. #include <strings.h>
  14. extern char *malloc();
  15. char *my_alloc();
  16. extern int atoi();
  17. char *save();
  18. #define TRUE 1
  19. #define FALSE 0
  20. #define MAGIC 4        /* distinguish compressed file from normal */
  21.  
  22. /*--------------- system configuration ------------------*/
  23.  
  24. /* define some parameters */
  25.  
  26. #define MAXCLASS 300        /* max # of classes */
  27. #define MAXLINE 256        /* max size of input line */
  28. #define MAXDEF 1000        /* max # bytes in a definition */
  29.  
  30. /* Define the default rulesfile */
  31.  
  32. #ifndef DEFFILE
  33. # define DEFFILE "headline"
  34. #endif
  35.  
  36. /* Define the environment variable which is to be interrogated for
  37.    name of rules file before DEFFILE is used. Delete this to
  38.    remove the code that calls getenv() */
  39.  
  40. #define ENVIRON "RULESFILE"
  41.  
  42. /* Define the random number generator */
  43.  
  44. extern long getpid();
  45. extern int rand(), srand();
  46.     /* SETRAND must be complete statement: note semicolon */
  47. #define SETRAND (void)srand((int) getpid() );
  48.     /* ROLL(n) returns integer 0..n-1 */
  49. #define ROLL(n) ((((long)rand()&0x7ffffff)>>5)%(n))
  50.  
  51. /* Enable '-d' dump debug option by defining DUMP */
  52. #define DUMP
  53.  
  54. /*---------------------------------------------------*/
  55.  
  56. FILE *InFile;
  57.  
  58. typedef struct def_struct{
  59.     int cumul;            /* cumulative weights */
  60.     char *string;            /* string which defines it */
  61.     struct def_struct *next;    /* link to next */
  62. } defn;
  63. defn *process();
  64. /*
  65.  * within a definition, names of subdefinitions are bracketed in BSLASH
  66.  * and SLASH chars. The whole definition ends with a '\0'.
  67.  * The SLASH character is always follwed by a variant tag - default is ' '.
  68.  */
  69. #define BSLASH '\\'
  70. #define SLASH  '/'
  71. #define VBAR     '|'
  72.  
  73. typedef struct{
  74.     int weight;    /* total weight of definitions in class */
  75.     defn *list;    /* list of them */
  76.     char *name;    /* name of this class */
  77.     char *tags;    /* pointer to list of tags */
  78. } class;
  79.  
  80. class * Class;    /* pointer to array of class records */
  81. char *NullTags = " ";    /* default tags ( shared ) */
  82. int Classes;    /* number of them */
  83. int HowMany = 1;
  84. int CompIn = FALSE;    /* is input file in compressed format? */
  85. int CompMain;        /* class # of MAIN class when compressed */
  86.  
  87. char InLine[MAXLINE];
  88.  
  89. main(argc, argv )
  90. int argc;
  91. char **argv;
  92. {
  93.     char *fname;
  94.     char main_class[20];
  95.     int i, c_flag = FALSE;
  96. #ifdef DUMP
  97.     int d_flag = FALSE;
  98. #endif DUMP
  99. #ifdef ENVIRON
  100.     extern char *getenv();
  101.     fname = getenv( ENVIRON );
  102. #else
  103.     fname = NULL;
  104. #endif ENVIRON
  105.  
  106.     while( argc > 1 ){
  107.         if( isdigit(*argv[1]) ){
  108.             HowMany = atoi(*++argv);
  109.             --argc;
  110.         }else if( strcmp( argv[1], "-c") == 0 ){
  111.             c_flag = TRUE;     /* 'compress' option */
  112.             --argc;
  113.             ++argv;
  114. #ifdef DUMP
  115.         }else if( strcmp( argv[1], "-d" )== 0 ){
  116.             d_flag = TRUE;    /* 'dump' option */
  117.             --argc;
  118.             ++argv;
  119. #endif DUMP
  120.         }else break;
  121.     }
  122.     if( argc > 1 ) fname = argv[1];
  123.     if (fname == NULL ) fname = DEFFILE;
  124.     InFile = fopen( fname, "r" );
  125.     if( InFile == NULL ){
  126.         fprintf( stderr, "Can\'t open: %s\n", fname );
  127.         exit(1);
  128.     }
  129.     init();
  130. #ifdef DUMP
  131.     if( d_flag ){
  132.         dump();
  133.         exit(0);
  134.     }
  135. #endif DUMP
  136.     if( c_flag ){
  137.         compress();
  138.     }else{
  139.         if( CompIn ) sprintf( main_class, "%d/ ", CompMain);
  140.         else         strcpy( main_class, "MAIN/ ");
  141.         for(i=0; i<HowMany; ++i) display(main_class,' ');
  142.     }
  143.     exit(0);
  144. }
  145.  
  146. init(){
  147.     int c;
  148.  
  149.     SETRAND        /* spin random number gen */
  150.     c = getc( InFile );    /* is compressed? */
  151.     CompIn = ( c== MAGIC );    /* set flag */
  152.     if( CompIn ){
  153.         readcomp();    /* read compressed version */
  154.     }else{
  155.         ungetc(c, InFile );
  156.         readtext();
  157.     }
  158. }
  159. readtext(){
  160.     register class *cp;
  161.     register defn *dp;
  162.     defn **update;
  163.     int clcomp();
  164.  
  165.     Class = (class *)my_alloc( (unsigned)(MAXCLASS * sizeof(class)) );
  166.     Classes = 0;
  167.  
  168.     cp = Class;
  169.     readline();
  170.     if( InLine[0]!='%'){
  171.         fprintf( stderr,"Class definition expected at: %s\n", InLine);
  172.         exit(1);
  173.     }
  174.     while( InLine[1] != '%' ){
  175.         if( Classes == MAXCLASS ){
  176.             fprintf(stderr,"Too many classes -- max = %d\n", MAXCLASS);
  177.             exit(1);
  178.         }
  179.         setup( cp );        /* set up the class struct */
  180.         readline();
  181.         if( InLine[0] == '%' ){
  182.             fprintf( stderr, "Expected class instance at: %s\n", InLine);
  183.             exit(1);
  184.         }
  185.         update = &(cp->list);    /* update pointer */
  186.         do{
  187.             dp = process();
  188.             *update = dp;
  189.             cp->weight += dp->cumul;    /* add new stuff */
  190.             dp->cumul = cp->weight;        /* set breakpoint */
  191.             update = &(dp->next);
  192.         }while( readline(), InLine[0]!= '%' );
  193.         ++Classes;        /* count them */
  194.         ++cp;
  195.         *update = NULL;
  196.     }
  197.     qsort( (char*)Class, Classes, sizeof( class ), clcomp);
  198. }
  199. /*
  200.  * display is given a class name ( delimited by SLASH, not '\0' ),
  201.  * and will (1) find its class descriptor, by calling lookup
  202.  * (2) pick a definition  (3) output that definition, and
  203.  * recursively display any definitions in it, and convert any escapes.
  204.  * The variant tag after the SLASH is used to pick out the appropriate
  205.  * variants. If that variant tag is '&', the tag 'deftag' is used, which
  206.  * is the active variant of the containing activation.
  207.  */
  208. display(s,deftag)
  209. char *s;
  210. int deftag;
  211. {
  212.     register class *cp;
  213.     register defn *dp;
  214.     register char *p;
  215.     class *lookup();
  216.     int i,variant,incurly;
  217.     register int c,writing;
  218.  
  219.     if( CompIn ){        /* input is compressed */
  220.         cp = &Class[ atoi(s) ];        /* explicit class # */
  221.     }else{
  222.         cp = lookup(s);
  223.         if( cp == NULL ) {        /* none found */
  224.             printf("???");
  225.             while( *s != SLASH ) putchar( *s++ );
  226.             printf("???");
  227.             return;
  228.         }
  229.     }
  230.     c = index(s,SLASH)[1];        /* get variant tag */
  231.     if( c != '&' ) deftag=c;    /* use given tag */
  232.     p = index(cp->tags, deftag);        /* look it up */
  233.     if(p == NULL ){
  234.         variant = 0;
  235.         printf("??/%c??", deftag );
  236.         deftag = ' ';        /* for passing as deftag */
  237.     }else variant = p - cp->tags;
  238.  
  239.     i = ROLL( cp->weight );
  240.     dp = cp->list;
  241.     while(dp->cumul <= i){    /* pick one based on cumul. weights */
  242.         dp = dp->next;
  243.     }
  244.  
  245.     incurly = 0;        /* not in curlies */
  246.     writing = 1;        /* writing */
  247.     p = dp->string;        /* this is the string */
  248.     for(;;)switch(c = *p++){
  249.         case '\0': return;
  250.         case BSLASH:
  251.             if(( c = *p++) == '\0' ) return; /* ?? */
  252.             else if( c == '!' ){
  253.                  if(writing)putchar('\n'); /* \! = newline */
  254.             }else if( isalnum(c) ){    /* reference */
  255.                 if(writing)display(p-1,deftag);  /* recurse */
  256.                 while( *p!=SLASH )++p;
  257.                 p += 2;        /* skip variant tag */
  258.             }else{
  259.                 if(writing) putchar(c);
  260.             }
  261.             break;
  262.         case '{':
  263.             if( !incurly ){
  264.                 incurly = 1;
  265.                 writing = (variant == 0 );
  266.             }else{
  267.                 if( writing )putchar('{');
  268.             }
  269.             break;
  270.         case VBAR:
  271.             if( incurly ){
  272.                 writing = ( variant == incurly++ );
  273.             }else{
  274.                 putchar(VBAR);
  275.             }
  276.             break;
  277.         case '}':
  278.             if( incurly ){
  279.                 writing = 1;
  280.                 incurly = 0;
  281.             }else putchar('}');
  282.             break;
  283.         default:
  284.             if( writing) putchar(c);
  285.     }
  286. }
  287. class *
  288. lookup( str )        /* delimited by SLASH, not '\0' */
  289. char *str;
  290. {
  291.     int first, last, try, comp;
  292.     int namecomp();
  293.  
  294.     first = 0;
  295.     last = Classes-1;
  296.     while( first <= last ){
  297.         try = (first+last)>>1;
  298.         comp = namecomp( str, Class[try].name );
  299.         if( comp == 0 ) return &Class[try];
  300.         if( comp > 0 ) first = try+1;
  301.         else last = try-1;
  302.     }
  303.     return NULL;
  304. }
  305. int namecomp(a,b)    /* 'a' is delim. by SLASH, 'b' by NULL */
  306. register char *a,*b;
  307. {
  308.     register int ac;
  309.     for(;;){
  310.         ac = *a++;
  311.         if(ac == SLASH ) ac = '\0';
  312.         if( ac < *b ) return -1;
  313.         if( ac > *b++ ) return 1;
  314.         if( ac == '\0' ) return 0;
  315.     }
  316. }
  317. readline(){
  318.     register char *p;
  319.     do{
  320.         if( fgets( InLine, MAXLINE, InFile ) == NULL ){
  321.             InLine[0] = InLine[1] = '%';
  322.             InLine[2] = '\0';    /* create EOF */
  323.         }else if( (p=rindex( InLine, '\n'))!= NULL ) *p = '\0';
  324.         p = InLine;
  325.         while( (p = index( p, BSLASH )) != NULL ){
  326.             if(p[1] == '*' ){
  327.                 *p = 0;    /* kill comment */
  328.                 break;
  329.             }else ++p;
  330.         }
  331.     }while( InLine[0] == '\0' );
  332. }
  333.  
  334. int clcomp(a,b)            
  335. register class *a,*b;
  336. {
  337.     if( a==b) retur